package com.zks.handler;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.NetUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.Log;
import cn.hutool.log.StaticLog;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.*;
import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.handler.codec.http.cookie.ServerCookieDecoder;
import io.netty.handler.codec.http.multipart.*;
import io.netty.util.CharsetUtil;
import io.netty.util.internal.StringUtil;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class Request {

    private static final Log log = StaticLog.get();

    private FullHttpRequest nettyRequest;
    //请求路径
    private String path;
    //请求ip
    private String ip;

    //头部信息
    private Map<String, String> headers = new HashMap<String, String>();
    //cookie 信息
    private Map<String, Cookie> cookies = new HashMap<String, Cookie>();
    //url 上的参数
    private Map<String, Object> params = new HashMap<String, Object>();

    private static final HttpDataFactory HTTP_DATA_FACTORY = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE);


    private Request(ChannelHandlerContext ctx, FullHttpRequest nettyRequest) {
       // System.out.println(nettyRequest.content().toString(CharsetUtil.UTF_8));
        this.nettyRequest = nettyRequest;
        final String uri = nettyRequest.uri();
        this.path = URLUtil.getPath(uri);
        this.putHeadersAndCookies(nettyRequest.headers());
        this.putParams(new QueryStringDecoder(uri));
        if (nettyRequest.method() != HttpMethod.GET) {
            //不是get 请求
            HttpPostRequestDecoder decoder = null;
            try {
                decoder = new HttpPostRequestDecoder(HTTP_DATA_FACTORY, nettyRequest);
                decoder.offer(nettyRequest);
                putParams(decoder);
            } finally {
                if (decoder != null) {
                    decoder.destroy();
                }
            }
        }
        this.putIp(ctx);
    }


    /**
     * 设置客户端ip
     *
     * @return void
     * @author zks
     * @date 2019/4/13 23:25
     */
    protected void putIp(ChannelHandlerContext ctx) {
        String ip = getHeader("X-Forwarded-For");
        if (!StringUtil.isNullOrEmpty(ip)) {
            ip = NetUtil.getMultistageReverseProxyIp(ip);
        } else {
            final InetSocketAddress inetSocketAddress = (InetSocketAddress) ctx.channel().remoteAddress();
            ip = inetSocketAddress.getAddress().getHostAddress();
        }
        this.ip = ip;

    }

    public String getHeader(String headerKey) {
        return headers.get(headerKey);
    }

    protected void putParams(HttpPostRequestDecoder decoder) {
        if (decoder == null) {
            return;
        }
        //raw 提交方式
        if(this.nettyRequest.content().isReadable()){
            String json=this.nettyRequest.content().toString(CharsetUtil.UTF_8);
            this.params.putAll(JSONUtil.toBean(json,HashMap.class));
        }
        //form 提交数据从这里获取
        for (InterfaceHttpData data : decoder.getBodyHttpDatas()) {
            putParam(data);
        }
    }

    protected void putParam(InterfaceHttpData data) {
        final InterfaceHttpData.HttpDataType dataType = data.getHttpDataType();
        if (dataType == InterfaceHttpData.HttpDataType.Attribute) {
            //普通参数
            Attribute attribute = (Attribute) data;
            try {
                this.putParam(attribute.getName(), attribute.getValue());
            } catch (IOException e) {
                log.error(e);
            }
        } else if (dataType == InterfaceHttpData.HttpDataType.FileUpload) {
            //文件上传
            FileUpload fileUpload = (FileUpload) data;
            if (fileUpload.isCompleted()) {
                try {
                    this.putParam(data.getName(), fileUpload.getFile());
                } catch (IOException e) {
                    log.error(e, "Get file param [{}] error!", data.getName());
                }

            }

        }


    }

    /**
     * get 请求填充参数
     *
     * @return void
     * @author zks
     * @date 2019/4/13 22:54
     */
    protected void putParams(QueryStringDecoder decoder) {
        if (decoder != null) {
            List<String> list;
            for (Map.Entry<String, List<String>> entry : decoder.parameters().entrySet()) {
                list = entry.getValue();
                if (CollectionUtil.isNotEmpty(list)) {
                    this.putParam(entry.getKey(), 1 == list.size() ? list.get(0) : list);
                }

            }

        }
    }

    /**
     * 填充参数
     *
     * @param key   参数名
     * @param value 参数值
     */
    protected void putParam(String key, Object value) {
        this.params.put(key, value);
    }

    /**
     * 填充头部信息和Cookie信息
     *
     * @param headers HttpHeaders
     */
    protected void putHeadersAndCookies(io.netty.handler.codec.http.HttpHeaders headers) {
        //封装头部信息
        for (Map.Entry<String, String> entry : headers) {
            this.headers.put(entry.getKey(), entry.getValue());
        }
        //封装cookie 信息
        final String cookieString = this.headers.get(HttpHeaderNames.COOKIE.toString());
        if (!StringUtil.isNullOrEmpty(cookieString)) {
            final Set<Cookie> cookieSet = ServerCookieDecoder.LAX.decode(cookieString);
            cookieSet.stream().forEach(cookie -> this.cookies.put(cookie.name(), cookie));
        }

    }

    protected final static Request build(ChannelHandlerContext ctx, FullHttpRequest nettyRequest) {
        return new Request(ctx, nettyRequest);

    }

    public String getPath() {
        return path;
    }


    public Object getParam(String key){
        return params.get(key);
    }


    public boolean isKeepAlive() {
        final String connectionHeader = getHeader(HttpHeaderNames.CONNECTION.toString());
        // 无论任何版本Connection为close时都关闭连接
        if (HttpHeaderValues.CLOSE.toString().equalsIgnoreCase(connectionHeader)) {
            return false;
        }

        // HTTP/1.0只有Connection为Keep-Alive时才会保持连接
        if (HttpVersion.HTTP_1_0.text().equals(getProtocolVersion())) {
            if (false == HttpHeaderValues.KEEP_ALIVE.toString().equalsIgnoreCase(connectionHeader)) {
                return false;
            }
        }
        // HTTP/1.1默认打开Keep-Alive
        return true;
    }


    public String getProtocolVersion() {
        return nettyRequest.protocolVersion().text();
    }

    public String getUri() {
        return nettyRequest.uri();
    }
}

